/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.github.florent37.camerafragment.sample.slice;

import com.github.florent37.camerafragment.internal.enums.MediaAction;
import com.github.florent37.camerafragment.internal.ui.view.AspectFrameLayout;
import com.github.florent37.camerafragment.internal.utils.ImageLoader;
import com.github.florent37.camerafragment.internal.utils.Log;
import com.github.florent37.camerafragment.internal.utils.Utils;
import com.github.florent37.camerafragment.sample.PreviewAbility;
import com.github.florent37.camerafragment.sample.ResourceTable;
import com.github.florent37.camerafragment.sample.bean.RxBusEvent;
import com.github.florent37.camerafragment.sample.rxbus.RxBus;

import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.Image;
import ohos.agp.components.Text;
import ohos.agp.components.surfaceprovider.SurfaceProvider;
import ohos.agp.graphics.SurfaceOps;
import ohos.global.resource.NotExistException;
import ohos.global.resource.WrongTypeException;
import ohos.media.audio.AudioManager;
import ohos.media.common.Source;
import ohos.media.player.Player;
import ohos.media.sessioncore.AVController;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * 拍照成功后预览页面
 *
 * @since 2021-05-18
 */
public class PreviewAbilitySlice extends AbilitySlice implements Component.ClickedListener {
    private static final String TAG = "PreviewAbilitySlice";
    private static final float CONSTANT_3 = 3f;
    private static final float CONSTANT_4 = 4f;
    private static final float CONSTANT_9 = 9f;
    private static final float CONSTANT_16 = 16f;
    private static final int ACTION_CONFIRM = 900;
    private static final int ACTION_RETAKE = 901;
    private static final int ACTION_CANCEL = 902;
    private static final int A_NEGATIVE = -1;
    private static final String MEDIA_ACTION_ARG = "media_action_arg";
    private static final String FILE_PATH_ARG = "file_path_arg";
    private static final String RESPONSE_CODE_ARG = "response_code_arg";
    private static final String VIDEO_POSITION_ARG = "current_video_position";
    private static final String VIDEO_IS_PLAYED_ARG = "is_played";
    private static final String MIME_TYPE_VIDEO = "VID";
    private static final String MIME_TYPE_IMAGE = "IMG";
    private int mediaAction;
    private String previewFilePath;
    private SurfaceProvider surfaceView;
    private Text ratioText;
    private Image imagePreview;
    private Player mediaPlayer;
    private Component cropMediaAction;
    private AVController mediaController;
    private ComponentContainer buttonPanel;
    private DirectionalLayout photoPreviewContainer;
    private AspectFrameLayout videoPreviewContainer;
    private DirectionalLayout ratioChanger;
    private int currentPlaybackPosition = 0;
    private int currentRatioIndex = 0;
    private boolean isVideoPlaying = true;
    private float[] ratios;
    private String[] ratioLabels;

    /**
     * 拍照后跳转该页面
     *
     * @param context 上下文
     * @param filePath 文件路径
     * @return Intent 意图
     */
    public static Intent newIntentPhoto(AbilitySlice context, String filePath) {
        Intent intent = new Intent();
        String bundleName = context.getAbilityInfo().getBundleName();
        Operation operation = new Intent.OperationBuilder()
            .withDeviceId("")
            .withBundleName(bundleName) // 包名
            .withAbilityName(PreviewAbility.class) // 跳转的ability
            .build();
        intent.setOperation(operation);
        intent.setParam(MEDIA_ACTION_ARG, MediaAction.ACTION_PHOTO);
        intent.setParam(FILE_PATH_ARG, filePath);
        return intent;
    }

    /**
     * 录像后跳转该页面
     *
     * @param context 上下文
     * @param filePath 文件路径
     * @return Intent 意图
     */
    public static Intent newIntentVideo(AbilitySlice context, String filePath) {
        Intent intent = new Intent();
        String bundleName = context.getAbilityInfo().getBundleName();
        Operation operation = new Intent.OperationBuilder()
            .withDeviceId("")
            .withBundleName(bundleName) // 包名
            .withAbilityName(PreviewAbility.class) // 跳转的ability
            .build();
        intent.setOperation(operation);
        intent.setParam(MEDIA_ACTION_ARG, MediaAction.ACTION_VIDEO);
        intent.setParam(FILE_PATH_ARG, filePath);
        return intent;
    }

    @Override
    protected void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_slice_preview);
        try {
            String originalRatioLabel = getContext().getResourceManager()
                .getElement(ResourceTable.String_preview_controls_original_ratio_label)
                .getString();
            ratioLabels = new String[]{originalRatioLabel, "1:1", "4:3", "16:9"};
            ratios = new float[]{0f, 1f, CONSTANT_4 / CONSTANT_3, CONSTANT_16 / CONSTANT_9};
        } catch (IOException e) {
            Log.error(TAG, "IOException:" + e.getLocalizedMessage());
        } catch (NotExistException e) {
            Log.error(TAG, "NotExistException:" + e.getLocalizedMessage());
        } catch (WrongTypeException e) {
            Log.error(TAG, "WrongTypeException:" + e.getLocalizedMessage());
        }
        surfaceView = (SurfaceProvider) findComponentById(ResourceTable.Id_video_preview);
        videoPreviewContainer = (AspectFrameLayout) findComponentById(ResourceTable.Id_previewAspectFrameLayout);
        photoPreviewContainer = (DirectionalLayout) findComponentById(ResourceTable.Id_photo_preview_container);
        buttonPanel = (ComponentContainer) findComponentById(ResourceTable.Id_preview_control_panel);
        Component confirmMediaResult = findComponentById(ResourceTable.Id_confirm_media_result);
        Component reTakeMedia = findComponentById(ResourceTable.Id_re_take_media);
        Component cancelMediaAction = findComponentById(ResourceTable.Id_cancel_media_action);
        if (confirmMediaResult != null) {
            confirmMediaResult.setClickedListener(this);
        }
        if (reTakeMedia != null) {
            reTakeMedia.setClickedListener(this);
        }
        if (cancelMediaAction != null) {
            cancelMediaAction.setClickedListener(this);
        }
        cropMediaAction = findComponentById(ResourceTable.Id_crop_image);
        ratioChanger = (DirectionalLayout) findComponentById(ResourceTable.Id_ratio_image);
        ratioText = (Text) findComponentById(ResourceTable.Id_ratio_text);
        ratioChanger.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                currentRatioIndex = (currentRatioIndex + 1) % ratios.length;
                ratioText.setText(ratioLabels[currentRatioIndex]);
            }
        });
        cropMediaAction.setVisibility(Component.HIDE);
        ratioChanger.setVisibility(Component.HIDE);

        display(intent);
    }

    private void display(Intent intent) {
        if (intent != null) {
            mediaAction = intent.getIntParam(MEDIA_ACTION_ARG, 0);
            previewFilePath = intent.getStringParam(FILE_PATH_ARG);
            if (mediaAction == MediaAction.ACTION_VIDEO) {
                displayVideo(intent);
            } else if (mediaAction == MediaAction.ACTION_PHOTO) {
                displayImage();
            } else {
                String mimeType = Utils.getMimeType(previewFilePath);
                if (mimeType.contains(MIME_TYPE_VIDEO)) {
                    displayVideo(intent);
                } else if (mimeType.contains(MIME_TYPE_IMAGE)) {
                    displayImage();
                } else {
                    terminate(); // 销毁页面
                }
            }
        }
    }

    // 页面不见时
    @Override
    protected void onStop() {
        super.onStop();
        if (mediaPlayer != null) {
            mediaPlayer.release();
            mediaPlayer = null;
        }
        if (mediaController != null) {
            mediaController = null;
        }
    }

    private void displayImage() {
        videoPreviewContainer.setVisibility(Component.HIDE);
        surfaceView.setVisibility(Component.HIDE);
        showImagePreview();
        ratioText.setText(ratioLabels[currentRatioIndex]);
    }

    private void showImagePreview() {
        imagePreview = new Image(this);
        ImageLoader.Builder builder = new ImageLoader.Builder(this); // 加载图片
        builder.load(previewFilePath).build().into(imagePreview);
        photoPreviewContainer.removeAllComponents();
        photoPreviewContainer.addComponent(imagePreview);
    }

    private void displayVideo(Intent savedInstanceState) {
        cropMediaAction.setVisibility(Component.HIDE);
        ratioChanger.setVisibility(Component.HIDE);
        if (savedInstanceState != null) {
            loadVideoParams(savedInstanceState);
        }
        photoPreviewContainer.setVisibility(Component.HIDE);
        mediaPlayer = new Player(this);
        surfaceView.getSurfaceOps().get().addCallback(new SurfaceOps.Callback() {
            @Override
            public void surfaceCreated(SurfaceOps surfaceOps) {
                showVideoPreview(surfaceOps);
            }

            @Override
            public void surfaceChanged(SurfaceOps surfaceOps, int ii, int i1, int i2) {
                Log.error(TAG, "surfaceChanged() called.");
            }

            @Override
            public void surfaceDestroyed(SurfaceOps surfaceOps) {
                Log.error(TAG, "surfaceDestroyed() called.");
            }
        });
    }

    private void showVideoPreview(SurfaceOps holder) {
        try {
            surfaceView.pinToZTop(true);
            surfaceView.setTop(0);
            File file = new File(previewFilePath); // 根据实际情况设置文件路径
            FileInputStream in = new FileInputStream(file);
            FileDescriptor fd = in.getFD(); // 从输入流获取FD对象
            Source source = new Source(fd);
            mediaPlayer.setSource(source);
            mediaPlayer.setSurfaceOps(holder);
            mediaPlayer.setVideoSurface(surfaceView.getSurfaceOps().get().getSurface());
            mediaPlayer.setAudioStreamType(AudioManager.AudioVolumeType.STREAM_MUSIC.getValue());
            mediaPlayer.prepare();
            mediaPlayer.setPlayerCallback(new PlayerCallback());
            int videoWidth = mediaPlayer.getVideoWidth();
            int videoHeight = mediaPlayer.getVideoHeight();

            videoPreviewContainer.setAspectRatio((double) videoWidth / videoHeight);

            mediaPlayer.play();
            mediaPlayer.rewindTo(currentPlaybackPosition);
            if (!isVideoPlaying) {
                mediaPlayer.pause();
            }
        } catch (IOException error) {
            Log.error(TAG, "Error media player playing video." + error.getLocalizedMessage());
        }
    }

    private void saveVideoParams(Intent outState) {
        if (mediaPlayer != null) {
            outState.setParam(VIDEO_POSITION_ARG, mediaPlayer.getCurrentTime());
            outState.setParam(VIDEO_IS_PLAYED_ARG, mediaPlayer.isNowPlaying());
        }
    }

    private void loadVideoParams(Intent savedInstanceState) {
        currentPlaybackPosition = savedInstanceState.getIntParam(VIDEO_POSITION_ARG, 0);
        isVideoPlaying = savedInstanceState.getBooleanParam(VIDEO_IS_PLAYED_ARG, true);
    }

    private void showButtonPanel(boolean isShow) {
        if (isShow) {
            buttonPanel.setVisibility(Component.VISIBLE);
        } else {
            buttonPanel.setVisibility(Component.HIDE);
        }
    }

    /**
     * 点击事件
     *
     * @param component 点击视图
     */
    @Override
    public void onClick(Component component) {
        Intent resultIntent = new Intent();
        switch (component.getId()) {
            case ResourceTable.Id_confirm_media_result:
                resultIntent.setParam(RESPONSE_CODE_ARG, ACTION_CONFIRM);
                break;
            case ResourceTable.Id_re_take_media:
                resultIntent.setParam(RESPONSE_CODE_ARG, ACTION_RETAKE);
                break;
            case ResourceTable.Id_cancel_media_action:
                resultIntent.setParam(RESPONSE_CODE_ARG, ACTION_CANCEL);
                break;
            default:
                break;
        }
        RxBusEvent busData = new RxBusEvent();
        busData.setIntent(resultIntent);
        RxBus.get(this).send(busData);
        terminate();
    }

    @Override
    protected void onBackPressed() {
        super.onBackPressed();
        Intent intent = new Intent();
        intent.setParam(RESPONSE_CODE_ARG, ACTION_CANCEL);
        RxBusEvent busData = new RxBusEvent();
        busData.setIntent(intent);
        RxBus.get(this).send(busData);
        terminate();
    }

    /**
     * 获取媒体文件路径
     *
     * @param resultIntent 意图
     * @return boolean获取结果
     */
    public static String getMediaFilePatch(Intent resultIntent) {
        return resultIntent.getStringParam(FILE_PATH_ARG);
    }

    /**
     * 返回结果
     *
     * @param resultIntent 意图
     * @return boolean获取结果
     */
    public static boolean isResultConfirm(Intent resultIntent) {
        return resultIntent.getIntParam(RESPONSE_CODE_ARG, A_NEGATIVE) == ACTION_CONFIRM;
    }

    /**
     * 重新录制
     *
     * @param resultIntent 意图
     * @return boolean获取结果
     */
    public static boolean isResultRetake(Intent resultIntent) {
        return resultIntent.getIntParam(RESPONSE_CODE_ARG, A_NEGATIVE) == ACTION_RETAKE;
    }

    /**
     * 取消结果
     *
     * @param resultIntent 意图
     * @return boolean获取结果
     */
    public static boolean isResultCancel(Intent resultIntent) {
        return resultIntent.getIntParam(RESPONSE_CODE_ARG, A_NEGATIVE) == ACTION_CANCEL;
    }

    /**
     * 播放回调
     *
     * @since 2021-05-18
     */
    private class PlayerCallback implements Player.IPlayerCallback {
        @Override
        public void onPrepared() {
            Log.error(TAG, "onPrepared");
        }

        @Override
        public void onMessage(int ii, int i1) {
        }

        @Override
        public void onError(int errorType, int errorCode) { // 播放失败
        }

        // 当视频大小改变时回调
        @Override
        public void onResolutionChanged(int ii, int i1) {
        }

        // 播放完成回调
        @Override
        public void onPlayBackComplete() {
            if (mediaPlayer != null) {
                mediaPlayer.stop();
                mediaPlayer = null;
            }
        }

        // 拖动完成进行回调
        @Override
        public void onRewindToComplete() {
        }

        // 缓冲更新  80代表80%
        @Override
        public void onBufferingChange(int ii) {
        }

        @Override
        public void onNewTimedMetaData(Player.MediaTimedMetaData mediaTimedMetaData) {
        }

        // 当播放持续被打断时会通过SeekTo记录
        @Override
        public void onMediaTimeIncontinuity(Player.MediaTimeInfo mediaTimeInfo) {
        }
    }
}
